闲话 22.12.9

闲话

我说我今天主要刷的是网络流题你信嘛(
主要是在上网课 然后老师讲课:“一说荒漠就会想到仙人掌”
就在群里发这题
浅看了一下发现不会 然后写了

是……辣个男人!他又来了(
image

有标号荒漠计数

P5434

我们定义一张图是荒漠,当且仅当其每个极大联通分量都是仙人掌。
给定 n,求有多少 n 个点的不同的荒漠。结果对 998244353 取模。

n105

首先要计数有标号荒漠,可以先计数有标号仙人掌。最后作 exp 就能得到答案。
注意答案是无根的,但是仙人掌显然是有根好统计一些。因此我们记 G 为有标号有根仙人掌计数的生成函数。考虑将一系列根连成环接在指定的一个根上,并由环没有方向,有

G=xexp(G+12i2Gi)=xexp(G+12(11G(1+G)))=xexp(G+G22(1G))=xexp(2GG22(1G))

无根考虑答案即为 [xn]exp(xG(x))
由于 exp 里面东西太多,我们考虑记

h(x)=2xx22(1x)

F 为答案计数的生成函数,有 F=x(exp(h(x)))
到这一步的话自然想到 Lagrange 反演。设 F=g(f(x)),有 G=x(g(f(x)))=x f(x) g(f(x))。现在只需要把另一部分化成同一形式就行了。

G=exp(h(G))+x(exp(h(G)))=exp(h(G))+x G h(G) exp(h(G)))=exp(h(G))(1+x G h(G))xG=xexp(h(G))(1+x G h(G))=G(1+x G h(G))=G+x G G h(G)G=xGx G G h(G)=xG(1G h(G))

自然导出了 f=G,g(x)=1xh(x)。记 H(x)=h(x)dx,有

g(x)=1xh(x)dx=xxh(x)dx=x(xh(x)h(x)dx)=xxh(x)+H(x)

这样我们需要的所有拼图都齐全了。拉格朗日反演得到

[xn]eF(x)=[xn]eg(f(x))=1n[xn1]g(x)eg(x)(xf1(x))

于是可以分别讨论三个(两个?)部分如何做。

g(x)

显然

下面需要 h(x)根据 Wolfram|Alpha,

h(x)=x22x22(1x)2

于是

g(x)=1xh(x)=1x32x22x2(1x)2=12x3+2x23x+1(1x)2

x/f1(x)

观察 f1 是个啥。其一是 f1(f(x))=x,其二是 f=xexp(2ff22(1f))。我们发现,假设 f1 中是连乘形式,且其中有 x 项,将 f(x) 带入后,只需要将后面的 exp 消除即可。
不妨考虑 f1(x)=xexp(x22x2(1x)),容易发现此函数满足需要。

因此我们能得到 x/f1(x)=exp(2xx22(1x))
因为上面还有一个 n 次方,该部分的贡献是 exp(n(2xx2)2(1x))

eg(x)

下面需要 H(x)根据 Wolfram|Alpha,

H(x)=14((x1)22ln(1x))

于是

g(x)=xxh(x)+H(x)=x+(x12)212ln(1x)x(2xx2)2(1x)=2x+x2412ln(1x)x(2xx2)2(1x)eg(x)=exp(2x+x2412ln(1x)x(2xx2)2(1x))[]=exp(2x+x2412ln(1x)x(2xx2)2(1x)+n(2xx2)2(1x))[]=(1x)1/2exp(2x+x24x(2xx2)2(1x)+n(2xx2)2(1x))[]=(1x)1/2exp(2x+x24+(nx)(2xx2)2(1x))[]=12x3+2x23x+1(1x)2/5exp(2x+x24+(nx)(2xx2)2(1x))

根据化简过程中不很简的部分,这玩意微分有限,存在线性递推,因此可以 O(n)/O(nlogn) 地算。

具体地,我们首先考察 a(x)=exp(2x+x24+(nx)(2xx2)2(1x))。求导后化简可以得到

2(1x)2a(x)=((2n+1)(2n+5)x+(n+4)x2x3)a(x)

过程 dirty,不细说了(

随后考察 b(x)=(1x)5/2a(x)。同理有

2(1x)2b(x)=((2n+6)(2n+10)x+(n+4)x2x3)b(x)

这自然导出了递推方案。答案即为

[xn/n!] b(x)(12x3+2x23x+1)

初值抄鰰的(
代码全屏好看(

code
#include <bits/stdc++.h>
using namespace std; using pii = pair<int,int>; using vi = vector<int>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
template <typename T> T rand(T l, T r) { return uniform_int_distribution<T>(l, r)(rnd); }
template <typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
template <typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define ufile(x) 
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define Aster(i, s) for (int i = head[s], v; i; i = e[i].next)
#define all(s) s.begin(), s.end()
#define eb emplace_back
#define pb pop_back
#define em emplace
const int N = 1e5 + 10, mod = 998244353, ans[] = {1, 1, 2, 8, 57};
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
int n, inv[N], fac;

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n;
    if (n <= 4) cout << ans[n], exit(0);
    inv[0] = inv[1] = fac = 1;
    rep(i,2,n) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod, fac = 1ll * fac * i % mod;
    vector<int> coef{ 0, 2 * n + 6, mod - (2 * n + 10), n + 4, mod - 1 },
    g{ 1, n + 3, ((1ll * (n + 7) * n >> 1) + 5) % mod, ((1ll * (n + 12) * n % mod + 42) * n % mod + 38) * inv[6] % mod };
    g.resize(n + 1);
    rep(i,4,n) {
        g[i] = (1ll * coef[1] * g[i - 1] % mod + 1ll * coef[2] * g[i - 2] % mod +
                1ll * coef[3] * g[i - 3] % mod + 1ll * coef[4] * g[i - 4] % mod) * inv[2] % mod;
        g[i] = (g[i] + 1ll * ((i - 1) << 1) * g[i - 1] % mod - 1ll * (i - 2) * g[i - 2] % mod + mod) % mod * inv[i] % mod;
    }
    fac = 1ll * fac * (g[n] - 3ll * g[n - 1] % mod + 2ll * g[n - 2] - 1ll * inv[2] * g[n - 3] % mod + 2 * mod) % mod;
    cout << (fac + mod) % mod << endl;
}

upd:使用 ODE+O(nlogn) 自动机,可以让计算机帮我们在 O(nlogn) 复杂度内完成。Submission

code
signed main() {
	int n; cin >> n;
	ODE B(2);
	B[0].redegree(3); B[1].redegree(2);
	B[0][3] = 1, B[0][2] = mod - n - 4, B[0][1] = 2 * n + 10, B[0][0] = mod - 2 * n - 6;
	B[1][2] = 2, B[1][1] = mod - 4, B[1][0] = 2;
	poly f(4); f[3] = mod - ginv(2), f[2] = 2, f[1] = mod - 3, f[0] = 1;
	ODE A = ode_power(1).composite(pfrac(topoly(f)));
	A = A * B;
	A.getPRec();
	auto l = A.trans_poly();
	int d = 0;
	for (int i = 0; i < l.size(); ++ i) d = max(d, l[i].degree());
	cout << 1ll * gfac(n) * p_recur(n, l.size() - 1, d, { 1, n, 
		int(1ll * "x^2 + x - 4"_p.eval(n) * ginv(2) % mod), 
		int(1ll * "x^3 + 3x^2 - 9x - 19"_p.eval(n) * ginv(6) % mod), 
		int(1ll * "x^4 + 6x^3 - 9x^2 - 88x - 87"_p.eval(n) * ginv(24) % mod), 
		int(1ll * "x^5 + 10x^4 + 5x^3 - 220x^2 - 685x - 452"_p.eval(n) * ginv(120) % mod), 
		int(1ll * "x^6 + 15x^5 + 45x^4 - 365x^3 - 2715x^2 - 5517x - 2600"_p.eval(n) * ginv(720) % mod)
		}, l.data()) % mod << endl;
}
posted @   joke3579  阅读(235)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示